#ifndef _QBUFFER_H_
#define _QBUFFER_H_

#include <cstring>
#include <string>
#include <memory>

using l64 = long long;
using ul64 = unsigned long long;
constexpr static l64 CAPDEF = 10;

class Fib
{
public:
    Fib() {}

    ///给定第一个大于sz的斐波那契数
    l64 Next(l64 sz)
    {
        l64 next = 0;
        do
        {
            next = mLast + mCurr;
            mLast = mCurr;
            mCurr = next;
        } while(next < sz);

        return next;
    }
private:
    l64 mLast {1};
    l64 mCurr {1};
};

class CharBuffer;
using SharedBuffer = std::shared_ptr<CharBuffer>;

class NonCopyable
{
public:
    NonCopyable() = default;
private:
    NonCopyable(const NonCopyable&) = delete;
    NonCopyable& operator=(const NonCopyable&) =delete;
};

///为了安全，QBuffer禁止对象的资源共享
/// 若要共享资源，使用智能指针
class CharBuffer : public NonCopyable
{
public:
    explicit CharBuffer(l64 capacity = CAPDEF);
    ///将常量存入buff
    CharBuffer(const char* data, l64 len);
    CharBuffer(const std::string& data);

    /// 是否可用包含一种方式，用来取得外部所分配空间的所有权
    /// 这样可以减少一次空间的分配，但可能在很多的场景并不适用
    /// QBuffer(...)

    ~CharBuffer();

    ///深拷贝，效率较低，拷贝后与数据相关的长度、容量、偏移量重置
    /// FIXME:可能不合适
    SharedBuffer Clone();

    ///向buff写入字符串类数据
    CharBuffer& Put(const char* data, l64 len);
    CharBuffer& Put(const std::string& data);
    CharBuffer& Put(const CharBuffer& buff);

    ///写入数值/布尔/包含內建的POD等类型
    template<typename NUMERIC>
    CharBuffer& Put(NUMERIC nu)
    {
        return Put((const char*)&nu, sizeof(NUMERIC));
    }
    ///从buff中读取数据
    template<typename T>
    bool Get(T* p, l64 len)
    {
        if(!enoughDataReaded(len))
            return false;

        memcpy(p, &mBuff[mDiff], len);
        diffForward(len);

        return true;
    }
    const char* Get()const;
    char *Get();

    l64 Length();
    bool IsNull();
private:
    ///还有指定长度的数据可读
    bool enoughDataReaded(l64 len);
    ///len为将要保存的数据的长度
    bool enoughSpaceSave(l64 len);
    ///读取len字节，修改mDiff
    void diffForward(l64 len);
    ///扩容
    void expand(l64 len);
private:
    ///当前已存的数据大小
    l64 mLength   {0};
    ///当前buff的总容量，随着数据的增大自动扩容
    l64 mCapacity {CAPDEF};
    ///读取buff的偏移量
    l64 mDiff{0};

    char*     mBuff{nullptr};

    ///使用斐波那契数列来进行扩容
    Fib mFib;
};

template<typename T>
void PackBufferImpl(SharedBuffer buff, const T& arg, ul64 len)
{
    buff->Put((char*)&arg, len);
}

template<typename T>
void PackBufferImpl(SharedBuffer buff, T* arg, ul64 len)
{
    buff->Put((char*)arg, len);
}

template<typename T, typename... R>
void PackBufferImpl(SharedBuffer buff, const T& val, ul64 len, R... args)
{
    PackBufferImpl(buff, val, len);
    PackBufferImpl(buff, args...);
}

template<typename T, typename... R>
SharedBuffer PackBuffer(const T& val, ul64 len, R... args)
{
    SharedBuffer buff(new CharBuffer());
    PackBufferImpl(buff, val, len, args...);

    return buff;
}

#endif
